package com.nkym.service.impl;


import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.nkym.common.ErrorCode;
import com.nkym.constants.UserConstant;
import com.nkym.exception.BusinessException;
import com.nkym.mapper.UserMapper;
import com.nkym.pojo.dto.user.SecretKeyRequest;
import com.nkym.pojo.dto.user.UserAddRequest;
import com.nkym.pojo.dto.user.UserLoginRequest;
import com.nkym.pojo.entity.User;
import com.nkym.service.UserService;
import com.nkym.utils.AESUtil;
import com.nkym.utils.RSAUtil;
import org.apache.commons.codec.DecoderException;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * @author 19637
 * @description 针对表【user】的数据库操作Service实现
 * @createDate 2023-04-22 17:10:24
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {
    //盐值
    private static final String SLAT = "lapi";

    @Resource
    UserMapper userMapper;


    @Override
    public String getSecretKey(String encryptData, HttpServletRequest request) {
        //经过RSA加密后的AES秘钥
        if (encryptData == null || encryptData.length() == 0) {
            throw new BusinessException("数据错误");
        }

        //AES秘钥 + iv
        String data = null;
        try {
            data = RSAUtil.decrypt(encryptData);
        } catch (Exception e) {
            throw new BusinessException("加密失败");
        }
        SecretKeyRequest secretKeyRequest = new Gson().fromJson(data, SecretKeyRequest.class);
        String key = secretKeyRequest.getKey();
        String iv = secretKeyRequest.getIv();

        //使用AES秘钥加密SecretKey
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute(UserConstant.USER_LOGIN_STATUS);
        if (user == null) {
            throw new BusinessException(ErrorCode.USER_UNLOGIN);
        }
        User currentUser = userMapper.selectById(user.getId());
        String secretKey = currentUser.getSecretKey();
        String res = null;
        try {
            res = AESUtil.encrypt(secretKey, key, iv);
        } catch (DecoderException e) {
            throw new BusinessException("加密失败");
        }
        return res;
    }

    @Override
    public User currentUser(HttpServletRequest request) {
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute(UserConstant.USER_LOGIN_STATUS);
        if (user == null) {
            throw new BusinessException(ErrorCode.USER_UNLOGIN);
        }
        User original = userMapper.selectById(user.getId());
        User safeUser = getSafeUser(original);
        return safeUser;
    }

    @Override
    public User userLogin(UserLoginRequest userLoginRequest, HttpServletRequest request, HttpServletResponse response) {
        String account = userLoginRequest.getAccount();
        String password = userLoginRequest.getPassword();
        if (account == null || password == null) {
            throw new BusinessException(ErrorCode.USER_LOGIN_ERROR);
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("account", account);

        //todo Redis缓存User数据


        User user = userMapper.selectOne(queryWrapper);
        // todo 使用布隆过滤器 防止缓存穿透
        if (user == null) {
            throw new BusinessException(ErrorCode.USER_LOGIN_ERROR);
        }
        String checkPassword = DigestUtil.md5Hex(SLAT + password);
        //校验密码
        if (!checkPassword.equals(user.getPassword())) {
            throw new BusinessException(ErrorCode.USER_LOGIN_ERROR);
        }
        //将数据信息放入Session
        HttpSession session = request.getSession();
        session.setAttribute(UserConstant.USER_LOGIN_STATUS, user);

        //敏感信息脱敏
        User safeUser = getSafeUser(user);
        return safeUser;
    }

    @Override
    public boolean registerUser(UserAddRequest userAddRequest) {
        String nickname = userAddRequest.getNickname();
        String account = userAddRequest.getAccount();
        String password = userAddRequest.getPassword();
        String checkPassword = userAddRequest.getCheckPassword();
        if (!StrUtil.isNotBlank(account) || account.length() < 6) {
            throw new BusinessException(ErrorCode.USER_REGISTER_ACCOUNT_ERROR);
        }
        if (!StrUtil.isNotBlank(password) || !StrUtil.isNotBlank(checkPassword) || !checkPassword.equals(password)) {
            throw new BusinessException(ErrorCode.USER_REGISTER_PASSWORD_ERROR);
        }
        if (nickname != null && nickname.length() > 30) {
            throw new BusinessException("名称过长");
        }
        if (nickname == null) {
            nickname = RandomUtil.randomString(6);
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("account", account);
        User existUser = userMapper.selectOne(queryWrapper);
        if (existUser != null) {
            throw new BusinessException(ErrorCode.USER_REGISTER_REPEAT);
        }
        //MD5盐值加密存储数据库
        password = DigestUtil.md5Hex(SLAT + password);
        User user = new User();
        user.setAccount(account);
        user.setPassword(password);
        //生成唯一ID  ，accessKey不能重复
        user.setNickname(nickname);
        String accessKey = IdUtil.objectId();
        String secretKey = RandomUtil.randomString(16);
        user.setAccessKey(accessKey);
        user.setSecretKey(secretKey);
        int i = userMapper.insert(user);
        return i > 0;
    }

    private User getSafeUser(User user) {
        User safeUser = new User();
        safeUser.setNickname(user.getNickname());
        safeUser.setId(user.getId());
        safeUser.setAccount(user.getAccount());
        safeUser.setAccessKey(user.getAccessKey());
        safeUser.setCreateTime(user.getCreateTime());
        safeUser.setUpdateTime(user.getUpdateTime());
        safeUser.setUserRole(user.getUserRole());
        return safeUser;
    }

}




